import { b2Color, b2Contact, b2ContactImpulse, b2ContactListener, b2Fixture, b2GetPointStates, b2Manifold, b2PointState, b2Vec2, b2World, b2WorldManifold, DrawAABBs, DrawCenterOfMasses, DrawJoints, DrawShapes } from "@box2d/core";
import { Matrix } from "../../math";
import { Settings } from "./settings";
import { g_camera } from "./utils/camera";
import { g_debugDraw } from "./utils/draw";


export interface TestConstructor {
    new(): PhysicalDebugDraw;
}

export class ContactPoint {
    public fixtureA!: b2Fixture;

    public fixtureB!: b2Fixture;

    public readonly normal = new b2Vec2();

    public readonly position = new b2Vec2();

    public state = b2PointState.b2_nullState;

    public normalImpulse = 0;

    public tangentImpulse = 0;

    public separation = 0;
}

export class PhysicalDebugDraw implements b2ContactListener {
    public static readonly k_maxContactPoints = 2048;

    public readonly m_points = Array.from({ length: PhysicalDebugDraw.k_maxContactPoints }, () => new ContactPoint());

    public m_pointCount = 0;

    public constructor() {

    }

    public BeginContact(_contact: b2Contact): void { }

    public EndContact(_contact: b2Contact): void { }

    private static PreSolve_s_state1: b2PointState[] = [
        /* b2_maxManifoldPoints */
    ];

    private static PreSolve_s_state2: b2PointState[] = [
        /* b2_maxManifoldPoints */
    ];

    private static PreSolve_s_worldManifold = new b2WorldManifold();

    public PreSolve(contact: b2Contact, oldManifold: b2Manifold): void {
        const manifold = contact.GetManifold();

        if (manifold.pointCount === 0) {
            return;
        }

        const fixtureA: b2Fixture | null = contact.GetFixtureA();
        const fixtureB: b2Fixture | null = contact.GetFixtureB();

        const state1 = PhysicalDebugDraw.PreSolve_s_state1;
        const state2 = PhysicalDebugDraw.PreSolve_s_state2;
        b2GetPointStates(state1, state2, oldManifold, manifold);

        const worldManifold = PhysicalDebugDraw.PreSolve_s_worldManifold;
        contact.GetWorldManifold(worldManifold);

        for (let i = 0; i < manifold.pointCount && this.m_pointCount < PhysicalDebugDraw.k_maxContactPoints; ++i) {
            const cp = this.m_points[this.m_pointCount];
            cp.fixtureA = fixtureA;
            cp.fixtureB = fixtureB;
            cp.position.Copy(worldManifold.points[i]);
            cp.normal.Copy(worldManifold.normal);
            cp.state = state2[i];
            cp.normalImpulse = manifold.points[i].normalImpulse;
            cp.tangentImpulse = manifold.points[i].tangentImpulse;
            cp.separation = worldManifold.separations[i];
            ++this.m_pointCount;
        }
    }

    public PostSolve(_contact: b2Contact, _impulse: b2ContactImpulse): void { }

    public draw(world: b2World, settings: Settings, globalViewportMatrix: Matrix): void {

        const ctx = g_debugDraw.m_ctx;

        const width = ctx.canvas.width;
        const height = ctx.canvas.height;

        // ctx.clearRect(0, 0, width, height);
        ctx.save();
        ctx.transform(globalViewportMatrix.a, globalViewportMatrix.b, globalViewportMatrix.c, globalViewportMatrix.d, globalViewportMatrix.tx, globalViewportMatrix.ty);
        // ctx.translate(0, g_camera.getHeight());
        // ctx.translate(0.5 * g_camera.getWidth(), 0.5 * g_camera.getHeight());
        ctx.scale(1, -1);
        // apply camera
        const zoom = g_camera.getZoom();
        ctx.scale(zoom, zoom);
        ctx.lineWidth /= zoom;
        const center = g_camera.getCenter();
        ctx.translate(-center.x, -center.y);

        //这里去除可不显示碰撞盒
        // if (settings.m_drawShapes) {
        //     DrawShapes(g_debugDraw, world);
        // }
        // if (settings.m_drawJoints) {
        //     DrawJoints(g_debugDraw, world);
        // }
        // if (settings.m_drawAABBs) {
        //     DrawAABBs(g_debugDraw, world);
        // }
        // if (settings.m_drawCOMs) {
        //     DrawCenterOfMasses(g_debugDraw, world);
        // }
        // // if (settings.m_drawControllers) {
        // //     DrawControllers(g_debugDraw, world);
        // // }

        // if (settings.m_drawContactPoints) {
        //     const k_impulseScale = 0.1;
        //     const k_axisScale = 0.3;

        //     for (let i = 0; i < this.m_pointCount; ++i) {
        //         const point = this.m_points[i];

        //         if (point.state === b2PointState.b2_addState) {
        //             // Add
        //             g_debugDraw.DrawPoint(point.position, 10, new b2Color(0.3, 0.95, 0.3));
        //         } else if (point.state === b2PointState.b2_persistState) {
        //             // Persist
        //             g_debugDraw.DrawPoint(point.position, 5, new b2Color(0.3, 0.3, 0.95));
        //         }

        //         if (settings.m_drawContactNormals) {
        //             const p1 = point.position;
        //             const p2 = b2Vec2.Add(p1, b2Vec2.Scale(k_axisScale, point.normal, b2Vec2.s_t0), new b2Vec2());
        //             g_debugDraw.DrawSegment(p1, p2, new b2Color(0.9, 0.9, 0.9));
        //         } else if (settings.m_drawContactImpulse) {
        //             const p1 = point.position;
        //             const p2 = b2Vec2.AddScaled(p1, k_impulseScale * point.normalImpulse, point.normal, new b2Vec2());
        //             g_debugDraw.DrawSegment(p1, p2, new b2Color(0.9, 0.9, 0.3));
        //         }

        //         if (settings.m_drawFrictionImpulse) {
        //             const tangent = b2Vec2.CrossVec2One(point.normal, new b2Vec2());
        //             const p1 = point.position;
        //             const p2 = b2Vec2.AddScaled(p1, k_impulseScale * point.tangentImpulse, tangent, new b2Vec2());
        //             g_debugDraw.DrawSegment(p1, p2, new b2Color(0.9, 0.9, 0.3));
        //         }
        //     }
        // }
        //以上都不影响运行
        this.m_pointCount = 0;
        ctx.restore();
    }

    public Destroy() { }
}